import os
import shutil
from datetime import datetime
from io import BytesIO

import minio
import qiniu
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import oss2

import C


class DiskStore():
    """
    本地存储
    """

    def save(self, body, path):
        path = f'{C.STORE_DIR}/{path}'
        if not os.path.exists(os.path.dirname(path)):
            os.makedirs(os.path.dirname(path))
        with open(path, mode='bw') as f:
            f.write(body)
        return path.replace('data/', '')

    def clearn(self, path):
        if not os.path.exists(path):
            return
        shutil.rmtree(path)


class CosStore():
    """
    腾讯云第三方存储
    """

    def __init__(self):
        c = C.config.get('cos', None)
        secretId = c['secretId']
        secretKey = c['secretKey']
        region = c['region']
        token = None
        scheme = 'https'
        config = CosConfig(Region=region, SecretId=secretId, SecretKey=secretKey, Token=token, Scheme=scheme)
        self.client = CosS3Client(config)
        self.bucket = c['bucket']
        self.uri = c['uri']
        print('__init__ cos client')

    __signle = None

    @classmethod
    def build(cls):
        if not cls.__signle:
            cls.__signle = CosStore()
        return cls.__signle

    def save(self, body, path):
        response = self.client.put_object(
            Bucket=self.bucket,
            Body=body,
            Key=path,
            # StorageClass='STANDARD',
            EnableMD5=False
        )
        url = self.uri + path
        print(f"cos put object: url={url}, etag={response['ETag']}")
        return url


class OssStore():
    """
    阿里云第三方存储
    """

    def __init__(self):
        c = C.config.get('oss', None)
        accessKeyId = c['accessKeyId']
        accessKeySecret = c['accessKeySecret']
        bucket_name = c['bucket']
        endpoint = c['endpoint']
        auth = oss2.Auth(accessKeyId, accessKeySecret)
        self.bucket = oss2.Bucket(auth, endpoint, bucket_name)
        self.uri = c['uri']
        print('__init__ oss client')

    __signle = None

    @classmethod
    def build(cls):
        if not cls.__signle:
            cls.__signle = OssStore()
        return cls.__signle

    def save(self, body, path):
        response = self.bucket.put_object(path, body)
        url = self.uri + path
        print(response)
        print(f"oss put object: url={url}, etag={response.etag}")
        return url


class KodoStore():
    import qiniu

    """
    七牛云第三方存储
    """

    def __init__(self):
        c = C.config.get('kodo', None)
        access_key = c['accessKey']
        secret_key = c['secretKey']
        bucket_name = c['bucket']
        # endpoint = c['endpoint']
        q = qiniu.Auth(access_key, secret_key)
        # self.bucket = oss2.Bucket(q, endpoint, bucket_name)
        self.uri = c['uri']
        self.q = q
        self.bucket_name = bucket_name
        print('__init__ kodo client')

    __signle = None

    @classmethod
    def build(cls):
        if not cls.__signle:
            cls.__signle = KodoStore()
        return cls.__signle

    def save(self, body, path):
        token = self.q.upload_token(self.bucket_name, path, 3600)
        r, info = qiniu.put_data(token, path, body)
        url = self.uri + path
        print(f"kodo put object: url={url}, hash={r['hash']}")
        return url


class MinioStore():
    from minio import Minio
    from minio.error import S3Error

    """
    minio存储
    https://pypi.org/project/minio/
    """

    def __init__(self):
        c = C.config.get('minio', None)
        access_key = c['accessKey']
        secret_key = c['secretKey']
        endpoint = c['endpoint']
        self.bucket_name = c['bucket']
        self.client = minio.Minio(endpoint, access_key, secret_key, secure=False)
        self.uri = c['uri']
        print('__init__ minio client')

    __signle = None

    @classmethod
    def build(cls):
        if not cls.__signle:
            cls.__signle = MinioStore()
        return cls.__signle

    def save(self, body, path):
        r = self.client.put_object(self.bucket_name, path, BytesIO(body), len(body))
        url = self.uri + self.bucket_name + '/' + path
        print(f"minio put object: url={url}, r={r}")
        return url


def save(body, filename, target='upload', rename=True):
    name = f'{C.code()}{os.path.splitext(filename)[1]}' if rename else filename
    day = datetime.strftime(datetime.now(), '%Y%m%d')
    path = f'{target}/{day}/{name}'
    cos = C.config.get('cos', None)
    if cos:
        return CosStore.build().save(body, path)
    oss = C.config.get('oss', None)
    if oss:
        return OssStore.build().save(body, path)
    _kodo = C.config.get('kodo', None)
    if _kodo:
        return KodoStore.build().save(body, path)
    _minio = C.config.get('minio', None)
    if _minio:
        return MinioStore.build().save(body, path)
    return DiskStore().save(body, path)
